Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.63% covered (success)
96.63%
1203 / 1245
56.52% covered (warning)
56.52%
13 / 23
CRAP
0.00% covered (danger)
0.00%
0 / 1
PptCharts
96.63% covered (success)
96.63%
1203 / 1245
56.52% covered (warning)
56.52%
13 / 23
218
0.00% covered (danger)
0.00%
0 / 1
 render
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
5.02
 writeChart
84.72% covered (warning)
84.72%
61 / 72
0.00% covered (danger)
0.00%
0 / 1
8.23
 writeSpreadsheet
93.75% covered (success)
93.75%
30 / 32
0.00% covered (danger)
0.00%
0 / 1
6.01
 writeElementWithValAttribute
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 writeSingleValueOrReference
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
2
 writeMultipleValuesOrReference
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
6
 writeTitle
100.00% covered (success)
100.00%
47 / 47
100.00% covered (success)
100.00%
1 / 1
4
 writePlotArea
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
12
 writeLegend
100.00% covered (success)
100.00%
47 / 47
100.00% covered (success)
100.00%
1 / 1
5
 writeLayout
76.92% covered (warning)
76.92%
20 / 26
0.00% covered (danger)
0.00%
0 / 1
5.31
 writeTypeArea
93.33% covered (success)
93.33%
42 / 45
0.00% covered (danger)
0.00%
0 / 1
9.02
 writeTypeBar
93.20% covered (success)
93.20%
96 / 103
0.00% covered (danger)
0.00%
0 / 1
17.09
 writeTypeBar3D
96.81% covered (success)
96.81%
91 / 94
0.00% covered (danger)
0.00%
0 / 1
15
 writeTypeDoughnut
95.40% covered (success)
95.40%
83 / 87
0.00% covered (danger)
0.00%
0 / 1
20
 writeTypePie
95.06% covered (success)
95.06%
77 / 81
0.00% covered (danger)
0.00%
0 / 1
15
 writeTypePie3D
100.00% covered (success)
100.00%
78 / 78
100.00% covered (success)
100.00%
1 / 1
13
 writeTypeLine
100.00% covered (success)
100.00%
83 / 83
100.00% covered (success)
100.00%
1 / 1
13
 writeTypeRadar
100.00% covered (success)
100.00%
81 / 81
100.00% covered (success)
100.00%
1 / 1
13
 writeTypeScatter
100.00% covered (success)
100.00%
87 / 87
100.00% covered (success)
100.00%
1 / 1
16
 writeChartRelationships
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 writeSeriesMarker
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
4
 writeAxis
99.42% covered (success)
99.42%
171 / 172
0.00% covered (danger)
0.00%
0 / 1
26
 writeAxisGridlines
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * This file is part of PHPPresentation - A pure PHP library for reading and writing
4 * presentations documents.
5 *
6 * PHPPresentation is free software distributed under the terms of the GNU Lesser
7 * General Public License version 3 as published by the Free Software Foundation.
8 *
9 * For the full copyright and license information, please read the LICENSE
10 * file that was distributed with this source code. For the full list of
11 * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors.
12 *
13 * @see        https://github.com/PHPOffice/PHPPresentation
14 *
15 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16 */
17
18declare(strict_types=1);
19
20namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;
21
22use PhpOffice\Common\Adapter\Zip\ZipInterface;
23use PhpOffice\Common\Drawing as CommonDrawing;
24use PhpOffice\Common\XMLWriter;
25use PhpOffice\PhpPresentation\Exception\FileRemoveException;
26use PhpOffice\PhpPresentation\Exception\UndefinedChartTypeException;
27use PhpOffice\PhpPresentation\PhpPresentation;
28use PhpOffice\PhpPresentation\Shape\Chart;
29use PhpOffice\PhpPresentation\Shape\Chart\Gridlines;
30use PhpOffice\PhpPresentation\Shape\Chart\Legend;
31use PhpOffice\PhpPresentation\Shape\Chart\PlotArea;
32use PhpOffice\PhpPresentation\Shape\Chart\Title;
33use PhpOffice\PhpPresentation\Shape\Chart\Type\Area;
34use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar;
35use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D;
36use PhpOffice\PhpPresentation\Shape\Chart\Type\Doughnut;
37use PhpOffice\PhpPresentation\Shape\Chart\Type\Line;
38use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie;
39use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D;
40use PhpOffice\PhpPresentation\Shape\Chart\Type\Radar;
41use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter;
42use PhpOffice\PhpPresentation\Style\Border;
43use PhpOffice\PhpPresentation\Style\Fill;
44use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
45use PhpOffice\PhpSpreadsheet\IOFactory;
46use PhpOffice\PhpSpreadsheet\Spreadsheet;
47
48class PptCharts extends AbstractDecoratorWriter
49{
50    public function render(): ZipInterface
51    {
52        for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) {
53            $shape = $this->getDrawingHashTable()->getByIndex($i);
54            if ($shape instanceof Chart) {
55                $this->getZip()->addFromString('ppt/charts/' . $shape->getIndexedFilename(), $this->writeChart($shape));
56
57                if ($shape->hasIncludedSpreadsheet()) {
58                    $this->getZip()->addFromString('ppt/charts/_rels/' . $shape->getIndexedFilename() . '.rels', $this->writeChartRelationships($shape));
59                    $pFilename = tempnam(sys_get_temp_dir(), 'PhpSpreadsheet');
60                    $this->getZip()->addFromString('ppt/embeddings/' . $shape->getIndexedFilename() . '.xlsx', $this->writeSpreadsheet($this->getPresentation(), $shape, $pFilename . '.xlsx'));
61
62                    // remove temp file
63                    if (false === @unlink($pFilename)) {
64                        throw new FileRemoveException($pFilename);
65                    }
66                }
67            }
68        }
69
70        return $this->getZip();
71    }
72
73    /**
74     * Write chart to XML format.
75     *
76     * @return string XML Output
77     */
78    protected function writeChart(Chart $chart): string
79    {
80        // Create XML writer
81        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
82
83        // XML header
84        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
85
86        // c:chartSpace
87        $objWriter->startElement('c:chartSpace');
88        $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
89        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
90        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
91
92        // c:date1904
93        $objWriter->startElement('c:date1904');
94        $objWriter->writeAttribute('val', '1');
95        $objWriter->endElement();
96
97        // c:lang
98        $objWriter->startElement('c:lang');
99        $objWriter->writeAttribute('val', 'en-US');
100        $objWriter->endElement();
101
102        // c:chart
103        $objWriter->startElement('c:chart');
104
105        // Title?
106        if ($chart->getTitle()->isVisible()) {
107            // Write title
108            $this->writeTitle($objWriter, $chart->getTitle());
109        }
110
111        // c:autoTitleDeleted
112        $objWriter->startElement('c:autoTitleDeleted');
113        $objWriter->writeAttribute('val', $chart->getTitle()->isVisible() ? '0' : '1');
114        $objWriter->endElement();
115
116        // c:view3D
117        $objWriter->startElement('c:view3D');
118
119        // c:rotX
120        $objWriter->startElement('c:rotX');
121        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationX());
122        $objWriter->endElement();
123
124        // c:hPercent
125        $hPercent = $chart->getView3D()->getHeightPercent();
126        $objWriter->writeElementIf(null != $hPercent, 'c:hPercent', 'val', $hPercent);
127
128        // c:rotY
129        $objWriter->startElement('c:rotY');
130        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationY());
131        $objWriter->endElement();
132
133        // c:depthPercent
134        $objWriter->startElement('c:depthPercent');
135        $objWriter->writeAttribute('val', $chart->getView3D()->getDepthPercent());
136        $objWriter->endElement();
137
138        // c:rAngAx
139        $objWriter->startElement('c:rAngAx');
140        $objWriter->writeAttribute('val', $chart->getView3D()->hasRightAngleAxes() ? '1' : '0');
141        $objWriter->endElement();
142
143        // c:perspective
144        $objWriter->startElement('c:perspective');
145        $objWriter->writeAttribute('val', $chart->getView3D()->getPerspective());
146        $objWriter->endElement();
147
148        $objWriter->endElement();
149
150        // Write plot area
151        $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart);
152
153        // Legend?
154        if ($chart->getLegend()->isVisible()) {
155            // Write legend
156            $this->writeLegend($objWriter, $chart->getLegend());
157        }
158
159        // c:plotVisOnly
160        $objWriter->startElement('c:plotVisOnly');
161        $objWriter->writeAttribute('val', '1');
162        $objWriter->endElement();
163
164        // c:dispBlanksAs
165        $objWriter->startElement('c:dispBlanksAs');
166        $objWriter->writeAttribute('val', $chart->getDisplayBlankAs());
167        $objWriter->endElement();
168
169        $objWriter->endElement();
170
171        // c:spPr
172        $objWriter->startElement('c:spPr');
173
174        // Fill
175        $this->writeFill($objWriter, $chart->getFill());
176
177        // Border
178        if (Border::LINE_NONE != $chart->getBorder()->getLineStyle()) {
179            $this->writeBorder($objWriter, $chart->getBorder(), '');
180        }
181
182        // Shadow
183        if ($chart->getShadow()->isVisible()) {
184            // a:effectLst
185            $objWriter->startElement('a:effectLst');
186
187            // a:outerShdw
188            $objWriter->startElement('a:outerShdw');
189            $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($chart->getShadow()->getBlurRadius()));
190            $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($chart->getShadow()->getDistance()));
191            $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle((int) $chart->getShadow()->getDirection()));
192            $objWriter->writeAttribute('algn', $chart->getShadow()->getAlignment());
193            $objWriter->writeAttribute('rotWithShape', '0');
194
195            $this->writeColor($objWriter, $chart->getShadow()->getColor(), $chart->getShadow()->getAlpha());
196
197            $objWriter->endElement();
198
199            $objWriter->endElement();
200        }
201
202        $objWriter->endElement();
203
204        // External data?
205        if ($chart->hasIncludedSpreadsheet()) {
206            // c:externalData
207            $objWriter->startElement('c:externalData');
208            $objWriter->writeAttribute('r:id', 'rId1');
209
210            // c:autoUpdate
211            $objWriter->startElement('c:autoUpdate');
212            $objWriter->writeAttribute('val', '0');
213            $objWriter->endElement();
214
215            $objWriter->endElement();
216        }
217
218        $objWriter->endElement();
219
220        // Return
221        return $objWriter->getData();
222    }
223
224    /**
225     * Write chart to XML format.
226     *
227     * @return string String output
228     */
229    protected function writeSpreadsheet(PhpPresentation $presentation, Chart $chart, string $tempName): string
230    {
231        // Create new spreadsheet
232        $spreadsheet = new Spreadsheet();
233
234        // Set properties
235        $title = $chart->getTitle()->getText();
236        if (0 == strlen($title)) {
237            $title = 'Chart';
238        }
239        $spreadsheet->getProperties()
240            ->setCreator(
241                $presentation->getDocumentProperties()->getCreator()
242            )
243            ->setLastModifiedBy(
244                $presentation->getDocumentProperties()->getLastModifiedBy()
245            )
246            ->setTitle($title);
247
248        // Add chart data
249        $sheet = $spreadsheet->setActiveSheetIndex(0);
250        $sheet->setTitle('Sheet1');
251
252        // Write series
253        $seriesIndex = 0;
254        foreach ($chart->getPlotArea()->getType()->getSeries() as $series) {
255            // Title
256            $sheet->setCellValueByColumnAndRow(2 + $seriesIndex, 1, $series->getTitle());
257
258            // X-axis
259            $axisXData = array_keys($series->getValues());
260            $numAxisXData = count($axisXData);
261            for ($i = 0; $i < $numAxisXData; ++$i) {
262                $sheet->setCellValueByColumnAndRow(1, $i + 2, $axisXData[$i]);
263            }
264
265            // Y-axis
266            $axisYData = array_values($series->getValues());
267            $numAxisYData = count($axisYData);
268            for ($i = 0; $i < $numAxisYData; ++$i) {
269                $sheet->setCellValueByColumnAndRow(2 + $seriesIndex, $i + 2, $axisYData[$i]);
270            }
271
272            ++$seriesIndex;
273        }
274
275        // Save to string
276        $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
277        $writer->save($tempName);
278
279        // Load file in memory
280        $returnValue = file_get_contents($tempName);
281        if (false === @unlink($tempName)) {
282            throw new FileRemoveException($tempName);
283        }
284
285        return $returnValue;
286    }
287
288    /**
289     * Write element with value attribute.
290     *
291     * @param XMLWriter $objWriter XML Writer
292     */
293    protected function writeElementWithValAttribute(XMLWriter $objWriter, string $elementName, string $value): void
294    {
295        $objWriter->startElement($elementName);
296        $objWriter->writeAttribute('val', $value);
297        $objWriter->endElement();
298    }
299
300    /**
301     * Write single value or reference.
302     *
303     * @param XMLWriter $objWriter XML Writer
304     */
305    protected function writeSingleValueOrReference(XMLWriter $objWriter, bool $isReference, string $value, string $reference): void
306    {
307        if (!$isReference) {
308            // Value
309            $objWriter->writeElement('c:v', $value);
310
311            return;
312        }
313
314        // Reference and cache
315        // c:strRef
316        $objWriter->startElement('c:strRef');
317        // c:strRef/c:f
318        $objWriter->writeElement('c:f', $reference);
319        // c:strRef/c:strCache
320        $objWriter->startElement('c:strCache');
321        // c:strRef/c:strCache/c:ptCount
322        $objWriter->startElement('c:ptCount');
323        $objWriter->writeAttribute('val', '1');
324        $objWriter->endElement();
325
326        // c:strRef/c:strCache/c:pt
327        $objWriter->startElement('c:pt');
328        $objWriter->writeAttribute('idx', '0');
329        // c:strRef/c:strCache/c:pt/c:v
330        $objWriter->writeElement('c:v', $value);
331        // c:strRef/c:strCache/c:pt
332        $objWriter->endElement();
333        // c:strRef/c:strCache
334        $objWriter->endElement();
335        // c:strRef
336        $objWriter->endElement();
337    }
338
339    /**
340     * Write series value or reference.
341     *
342     * @param XMLWriter $objWriter XML Writer
343     * @param array<int, mixed> $values
344     */
345    protected function writeMultipleValuesOrReference(XMLWriter $objWriter, bool $isReference, array $values, string $reference): void
346    {
347        // c:strLit / c:numLit
348        // c:strRef / c:numRef
349        $referenceType = ($isReference ? 'Ref' : 'Lit');
350        $dataType = is_numeric($values[0]) ? 'num' : 'str';
351        $objWriter->startElement('c:' . $dataType . $referenceType);
352
353        $numValues = count($values);
354        if (!$isReference) {
355            // Value
356
357            // c:ptCount
358            $objWriter->startElement('c:ptCount');
359            $objWriter->writeAttribute('val', count($values));
360            $objWriter->endElement();
361
362            // Add points
363            for ($i = 0; $i < $numValues; ++$i) {
364                // c:pt
365                $objWriter->startElement('c:pt');
366                $objWriter->writeAttribute('idx', $i);
367                $objWriter->writeElement('c:v', (string) ($values[$i]));
368                $objWriter->endElement();
369            }
370        } else {
371            // Reference
372            $objWriter->writeElement('c:f', $reference);
373            $objWriter->startElement('c:' . $dataType . 'Cache');
374
375            // c:ptCount
376            $objWriter->startElement('c:ptCount');
377            $objWriter->writeAttribute('val', count($values));
378            $objWriter->endElement();
379
380            // Add points
381            for ($i = 0; $i < $numValues; ++$i) {
382                // c:pt
383                $objWriter->startElement('c:pt');
384                $objWriter->writeAttribute('idx', $i);
385                $objWriter->writeElement('c:v', (string) ($values[$i]));
386                $objWriter->endElement();
387            }
388
389            $objWriter->endElement();
390        }
391
392        $objWriter->endElement();
393    }
394
395    /**
396     * Write Title.
397     */
398    protected function writeTitle(XMLWriter $objWriter, Title $subject): void
399    {
400        // c:title
401        $objWriter->startElement('c:title');
402
403        // c:tx
404        $objWriter->startElement('c:tx');
405
406        // c:rich
407        $objWriter->startElement('c:rich');
408
409        // a:bodyPr
410        $objWriter->writeElement('a:bodyPr', null);
411
412        // a:lstStyle
413        $objWriter->writeElement('a:lstStyle', null);
414
415        // a:p
416        $objWriter->startElement('a:p');
417
418        // a:pPr
419        $objWriter->startElement('a:pPr');
420        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
421        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
422        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
423        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
424        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
425        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
426
427        // a:defRPr
428        $objWriter->writeElement('a:defRPr', null);
429
430        $objWriter->endElement();
431
432        // a:r
433        $objWriter->startElement('a:r');
434
435        // a:rPr
436        $objWriter->startElement('a:rPr');
437        $objWriter->writeAttribute('lang', 'en-US');
438        $objWriter->writeAttribute('dirty', '0');
439        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
440        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
441        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
442        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
443        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
444        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
445        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
446
447        // Font - a:solidFill
448        $objWriter->startElement('a:solidFill');
449
450        $this->writeColor($objWriter, $subject->getFont()->getColor());
451
452        $objWriter->endElement();
453
454        // Font - a:latin
455        $objWriter->startElement('a:latin');
456        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
457        $objWriter->endElement();
458
459        $objWriter->endElement();
460
461        // a:t
462        $objWriter->writeElement('a:t', $subject->getText());
463
464        $objWriter->endElement();
465
466        // a:endParaRPr
467        $objWriter->startElement('a:endParaRPr');
468        $objWriter->writeAttribute('lang', 'en-US');
469        $objWriter->writeAttribute('dirty', '0');
470        $objWriter->endElement();
471
472        $objWriter->endElement();
473
474        $objWriter->endElement();
475
476        $objWriter->endElement();
477
478        // Write layout
479        $this->writeLayout($objWriter, $subject);
480
481        // c:overlay
482        $objWriter->startElement('c:overlay');
483        $objWriter->writeAttribute('val', '0');
484        $objWriter->endElement();
485
486        $objWriter->endElement();
487    }
488
489    /**
490     * Write Plot Area.
491     *
492     * @param XMLWriter $objWriter XML Writer
493     */
494    protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart $chart): void
495    {
496        // c:plotArea
497        $objWriter->startElement('c:plotArea');
498
499        // Write layout
500        $this->writeLayout($objWriter, $subject);
501
502        // Write chart
503        $chartType = $subject->getType();
504        if ($chartType instanceof Area) {
505            $this->writeTypeArea($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
506        } elseif ($chartType instanceof Bar) {
507            $this->writeTypeBar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
508        } elseif ($chartType instanceof Bar3D) {
509            $this->writeTypeBar3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
510        } elseif ($chartType instanceof Doughnut) {
511            $this->writeTypeDoughnut($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
512        } elseif ($chartType instanceof Pie) {
513            $this->writeTypePie($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
514        } elseif ($chartType instanceof Pie3D) {
515            $this->writeTypePie3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
516        } elseif ($chartType instanceof Line) {
517            $this->writeTypeLine($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
518        } elseif ($chartType instanceof Radar) {
519            $this->writeTypeRadar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
520        } elseif ($chartType instanceof Scatter) {
521            $this->writeTypeScatter($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
522        } else {
523            throw new UndefinedChartTypeException();
524        }
525
526        // Write X axis?
527        if ($chartType->hasAxisX()) {
528            $this->writeAxis($objWriter, $subject->getAxisX(), Chart\Axis::AXIS_X, $chartType);
529        }
530
531        // Write Y axis?
532        if ($chartType->hasAxisY()) {
533            $this->writeAxis($objWriter, $subject->getAxisY(), Chart\Axis::AXIS_Y, $chartType);
534        }
535
536        $objWriter->endElement();
537    }
538
539    /**
540     * Write Legend.
541     *
542     * @param XMLWriter $objWriter XML Writer
543     * @param Chart\Legend $subject
544     */
545    protected function writeLegend(XMLWriter $objWriter, Legend $subject): void
546    {
547        // c:legend
548        $objWriter->startElement('c:legend');
549
550        // c:legendPos
551        $objWriter->startElement('c:legendPos');
552        $objWriter->writeAttribute('val', $subject->getPosition());
553        $objWriter->endElement();
554
555        // Write layout
556        $this->writeLayout($objWriter, $subject);
557
558        // c:overlay
559        $objWriter->startElement('c:overlay');
560        $objWriter->writeAttribute('val', '0');
561        $objWriter->endElement();
562
563        // c:spPr
564        $objWriter->startElement('c:spPr');
565
566        // Fill
567        $this->writeFill($objWriter, $subject->getFill());
568
569        // Border
570        if (Border::LINE_NONE != $subject->getBorder()->getLineStyle()) {
571            $this->writeBorder($objWriter, $subject->getBorder(), '');
572        }
573
574        $objWriter->endElement();
575
576        // c:txPr
577        $objWriter->startElement('c:txPr');
578
579        // a:bodyPr
580        $objWriter->writeElement('a:bodyPr', null);
581
582        // a:lstStyle
583        $objWriter->writeElement('a:lstStyle', null);
584
585        // a:p
586        $objWriter->startElement('a:p');
587
588        // a:pPr
589        $objWriter->startElement('a:pPr');
590        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
591        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
592        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
593        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
594        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
595        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
596
597        // a:defRPr
598        $objWriter->startElement('a:defRPr');
599
600        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
601        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
602        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
603        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
604        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
605        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
606        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
607
608        // Font - a:solidFill
609        $objWriter->startElement('a:solidFill');
610
611        $this->writeColor($objWriter, $subject->getFont()->getColor());
612
613        $objWriter->endElement();
614
615        // Font - a:latin
616        $objWriter->startElement('a:latin');
617        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
618        $objWriter->endElement();
619
620        $objWriter->endElement();
621
622        $objWriter->endElement();
623
624        // a:endParaRPr
625        $objWriter->startElement('a:endParaRPr');
626        $objWriter->writeAttribute('lang', 'en-US');
627        $objWriter->writeAttribute('dirty', '0');
628        $objWriter->endElement();
629
630        $objWriter->endElement();
631
632        $objWriter->endElement();
633
634        $objWriter->endElement();
635    }
636
637    /**
638     * Write Layout.
639     *
640     * @param XMLWriter $objWriter XML Writer
641     * @param Legend|PlotArea|Title $subject
642     */
643    protected function writeLayout(XMLWriter $objWriter, $subject): void
644    {
645        // c:layout
646        $objWriter->startElement('c:layout');
647
648        // c:manualLayout
649        $objWriter->startElement('c:manualLayout');
650        // c:xMode
651        $objWriter->startElement('c:xMode');
652        $objWriter->writeAttribute('val', 'edge');
653        $objWriter->endElement();
654
655        // c:yMode
656        $objWriter->startElement('c:yMode');
657        $objWriter->writeAttribute('val', 'edge');
658        $objWriter->endElement();
659
660        if (0 != $subject->getOffsetX()) {
661            // c:x
662            $objWriter->startElement('c:x');
663            $objWriter->writeAttribute('val', $subject->getOffsetX());
664            $objWriter->endElement();
665        }
666
667        if (0 != $subject->getOffsetY()) {
668            // c:y
669            $objWriter->startElement('c:y');
670            $objWriter->writeAttribute('val', $subject->getOffsetY());
671            $objWriter->endElement();
672        }
673
674        if (0 != $subject->getWidth()) {
675            // c:w
676            $objWriter->startElement('c:w');
677            $objWriter->writeAttribute('val', $subject->getWidth());
678            $objWriter->endElement();
679        }
680
681        if (0 != $subject->getHeight()) {
682            // c:h
683            $objWriter->startElement('c:h');
684            $objWriter->writeAttribute('val', $subject->getHeight());
685            $objWriter->endElement();
686        }
687
688        $objWriter->endElement();
689        $objWriter->endElement();
690    }
691
692    /**
693     * Write Type Area.
694     *
695     * @param XMLWriter $objWriter XML Writer
696     * @param Chart\Type\Area $subject
697     */
698    protected function writeTypeArea(XMLWriter $objWriter, Area $subject, bool $includeSheet = false): void
699    {
700        // c:lineChart
701        $objWriter->startElement('c:areaChart');
702
703        // c:grouping
704        $objWriter->startElement('c:grouping');
705        $objWriter->writeAttribute('val', 'standard');
706        $objWriter->endElement();
707
708        // Write series
709        $seriesIndex = 0;
710        foreach ($subject->getSeries() as $series) {
711            // c:ser
712            $objWriter->startElement('c:ser');
713
714            // c:ser > c:idx
715            $objWriter->startElement('c:idx');
716            $objWriter->writeAttribute('val', $seriesIndex);
717            $objWriter->endElement();
718
719            // c:ser > c:order
720            $objWriter->startElement('c:order');
721            $objWriter->writeAttribute('val', $seriesIndex);
722            $objWriter->endElement();
723
724            // c:ser > c:tx
725            $objWriter->startElement('c:tx');
726            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
727            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
728            $objWriter->endElement();
729
730            // c:ser > c:dLbls
731            // @link : https://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.charts.areachartseries.aspx
732            $objWriter->startElement('c:dLbls');
733
734            // c:ser > c:dLbls > c:showVal
735            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
736
737            // c:ser > c:dLbls > c:showCatName
738            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
739
740            // c:ser > c:dLbls > c:showSerName
741            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
742
743            // c:ser > c:dLbls > c:showPercent
744            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
745
746            // c:ser > ##c:dLbls
747            $objWriter->endElement();
748
749            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
750                // c:spPr
751                $objWriter->startElement('c:spPr');
752                // Write fill
753                $this->writeFill($objWriter, $series->getFill());
754                // ## c:spPr
755                $objWriter->endElement();
756            }
757
758            // Write X axis data
759            $axisXData = array_keys($series->getValues());
760
761            // c:cat
762            $objWriter->startElement('c:cat');
763            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
764            $objWriter->endElement();
765
766            // Write Y axis data
767            $axisYData = array_values($series->getValues());
768
769            // c:val
770            $objWriter->startElement('c:val');
771            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
772            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
773            $objWriter->endElement();
774
775            $objWriter->endElement();
776
777            ++$seriesIndex;
778        }
779
780        // c:axId
781        $objWriter->startElement('c:axId');
782        $objWriter->writeAttribute('val', '52743552');
783        $objWriter->endElement();
784
785        // c:axId
786        $objWriter->startElement('c:axId');
787        $objWriter->writeAttribute('val', '52749440');
788        $objWriter->endElement();
789
790        $objWriter->endElement();
791    }
792
793    /**
794     * Write Type Bar.
795     *
796     * @param XMLWriter $objWriter XML Writer
797     * @param Chart\Type\Bar $subject
798     */
799    protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includeSheet = false): void
800    {
801        // c:barChart
802        $objWriter->startElement('c:barChart');
803
804        // c:barDir
805        $objWriter->startElement('c:barDir');
806        $objWriter->writeAttribute('val', $subject->getBarDirection());
807        $objWriter->endElement();
808
809        // c:grouping
810        $objWriter->startElement('c:grouping');
811        $objWriter->writeAttribute('val', $subject->getBarGrouping());
812        $objWriter->endElement();
813
814        // Write series
815        $seriesIndex = 0;
816        foreach ($subject->getSeries() as $series) {
817            // c:ser
818            $objWriter->startElement('c:ser');
819
820            // c:idx
821            $objWriter->startElement('c:idx');
822            $objWriter->writeAttribute('val', $seriesIndex);
823            $objWriter->endElement();
824
825            // c:order
826            $objWriter->startElement('c:order');
827            $objWriter->writeAttribute('val', $seriesIndex);
828            $objWriter->endElement();
829
830            // c:tx
831            $objWriter->startElement('c:tx');
832            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
833            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
834            $objWriter->endElement();
835
836            // Fills for points?
837            $dataPointFills = $series->getDataPointFills();
838            foreach ($dataPointFills as $key => $value) {
839                // c:dPt
840                $objWriter->startElement('c:dPt');
841
842                // c:idx
843                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
844
845                if (Fill::FILL_NONE != $value->getFillType()) {
846                    // c:spPr
847                    $objWriter->startElement('c:spPr');
848                    // Write fill
849                    $this->writeFill($objWriter, $value);
850                    // ## c:spPr
851                    $objWriter->endElement();
852                }
853
854                // ## c:dPt
855                $objWriter->endElement();
856            }
857
858            // c:dLbls
859            $objWriter->startElement('c:dLbls');
860
861            if ($series->hasDlblNumFormat()) {
862                //c:numFmt
863                $objWriter->startElement('c:numFmt');
864                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
865                $objWriter->writeAttribute('sourceLinked', '0');
866                $objWriter->endElement();
867            }
868
869            // c:txPr
870            $objWriter->startElement('c:txPr');
871
872            // a:bodyPr
873            $objWriter->writeElement('a:bodyPr');
874
875            // a:lstStyle
876            $objWriter->writeElement('a:lstStyle');
877
878            // a:p
879            $objWriter->startElement('a:p');
880
881            // a:pPr
882            $objWriter->startElement('a:pPr');
883
884            // a:defRPr
885            $objWriter->startElement('a:defRPr');
886            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
887            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
888            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
889            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
890            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
891            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
892            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
893
894            // a:solidFill
895            $objWriter->startElement('a:solidFill');
896            $this->writeColor($objWriter, $series->getFont()->getColor());
897            $objWriter->endElement();
898
899            // a:latin
900            $objWriter->startElement('a:latin');
901            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
902            $objWriter->endElement();
903
904            // a:ea
905            $objWriter->startElement('a:ea');
906            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
907            $objWriter->endElement();
908
909            // >a:defRPr
910            $objWriter->endElement();
911            // >a:pPr
912            $objWriter->endElement();
913
914            // a:endParaRPr
915            $objWriter->startElement('a:endParaRPr');
916            $objWriter->writeAttribute('lang', 'en-US');
917            $objWriter->writeAttribute('dirty', '0');
918            $objWriter->endElement();
919
920            // >a:p
921            $objWriter->endElement();
922            // >a:lstStyle
923            $objWriter->endElement();
924
925            // c:dLblPos
926            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
927
928            // c:showVal
929            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
930
931            // c:showCatName
932            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
933
934            // c:showSerName
935            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
936
937            // c:showPercent
938            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
939
940            // c:separator
941            $objWriter->writeElement('c:separator', $series->hasShowSeparator() ? $series->getSeparator() : '');
942
943            // c:showLeaderLines
944            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
945
946            $objWriter->endElement();
947
948            // c:spPr
949            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
950                // c:spPr
951                $objWriter->startElement('c:spPr');
952                // Write fill
953                $this->writeFill($objWriter, $series->getFill());
954                // ## c:spPr
955                $objWriter->endElement();
956            }
957
958            // Write X axis data
959            $axisXData = array_keys($series->getValues());
960
961            // c:cat
962            $objWriter->startElement('c:cat');
963            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
964            $objWriter->endElement();
965
966            // Write Y axis data
967            $axisYData = array_values($series->getValues());
968
969            // c:val
970            $objWriter->startElement('c:val');
971            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
972            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
973            $objWriter->endElement();
974
975            $objWriter->endElement();
976
977            ++$seriesIndex;
978        }
979
980        // c:gapWidth
981        $objWriter->startElement('c:gapWidth');
982        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
983        $objWriter->endElement();
984
985        // c:overlap
986        $objWriter->startElement('c:overlap');
987        $objWriter->writeAttribute('val', $subject->getOverlapWidthPercent());
988        $objWriter->endElement();
989
990        // c:axId
991        $objWriter->startElement('c:axId');
992        $objWriter->writeAttribute('val', '52743552');
993        $objWriter->endElement();
994
995        // c:axId
996        $objWriter->startElement('c:axId');
997        $objWriter->writeAttribute('val', '52749440');
998        $objWriter->endElement();
999
1000        // c:extLst
1001        $objWriter->startElement('c:extLst');
1002        $objWriter->endElement();
1003
1004        $objWriter->endElement();
1005    }
1006
1007    /**
1008     * Write Type Bar3D.
1009     *
1010     * @param XMLWriter $objWriter XML Writer
1011     * @param Chart\Type\Bar3D $subject
1012     */
1013    protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, bool $includeSheet = false): void
1014    {
1015        // c:bar3DChart
1016        $objWriter->startElement('c:bar3DChart');
1017
1018        // c:barDir
1019        $objWriter->startElement('c:barDir');
1020        $objWriter->writeAttribute('val', $subject->getBarDirection());
1021        $objWriter->endElement();
1022
1023        // c:grouping
1024        $objWriter->startElement('c:grouping');
1025        $objWriter->writeAttribute('val', $subject->getBarGrouping());
1026        $objWriter->endElement();
1027
1028        // Write series
1029        $seriesIndex = 0;
1030        foreach ($subject->getSeries() as $series) {
1031            // c:ser
1032            $objWriter->startElement('c:ser');
1033
1034            // c:idx
1035            $objWriter->startElement('c:idx');
1036            $objWriter->writeAttribute('val', $seriesIndex);
1037            $objWriter->endElement();
1038
1039            // c:order
1040            $objWriter->startElement('c:order');
1041            $objWriter->writeAttribute('val', $seriesIndex);
1042            $objWriter->endElement();
1043
1044            // c:tx
1045            $objWriter->startElement('c:tx');
1046            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1047            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1048            $objWriter->endElement();
1049
1050            // Fills for points?
1051            $dataPointFills = $series->getDataPointFills();
1052            foreach ($dataPointFills as $key => $value) {
1053                // c:dPt
1054                $objWriter->startElement('c:dPt');
1055
1056                // c:idx
1057                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1058
1059                if (Fill::FILL_NONE != $value->getFillType()) {
1060                    // c:spPr
1061                    $objWriter->startElement('c:spPr');
1062                    // Write fill
1063                    $this->writeFill($objWriter, $value);
1064                    // ## c:spPr
1065                    $objWriter->endElement();
1066                }
1067
1068                // ## c:dPt
1069                $objWriter->endElement();
1070            }
1071
1072            // c:dLbls
1073            $objWriter->startElement('c:dLbls');
1074
1075            // c:txPr
1076            $objWriter->startElement('c:txPr');
1077
1078            // a:bodyPr
1079            $objWriter->writeElement('a:bodyPr', null);
1080
1081            // a:lstStyle
1082            $objWriter->writeElement('a:lstStyle', null);
1083
1084            // a:p
1085            $objWriter->startElement('a:p');
1086
1087            // a:pPr
1088            $objWriter->startElement('a:pPr');
1089
1090            // a:defRPr
1091            $objWriter->startElement('a:defRPr');
1092
1093            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1094            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1095            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1096            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1097            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1098            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1099            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1100
1101            // Font - a:solidFill
1102            $objWriter->startElement('a:solidFill');
1103
1104            $this->writeColor($objWriter, $series->getFont()->getColor());
1105
1106            $objWriter->endElement();
1107
1108            // Font - a:latin
1109            $objWriter->startElement('a:latin');
1110            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1111            $objWriter->endElement();
1112            // a:ea
1113            $objWriter->startElement('a:ea');
1114            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1115            $objWriter->endElement();
1116
1117            $objWriter->endElement();
1118
1119            $objWriter->endElement();
1120
1121            // a:endParaRPr
1122            $objWriter->startElement('a:endParaRPr');
1123            $objWriter->writeAttribute('lang', 'en-US');
1124            $objWriter->writeAttribute('dirty', '0');
1125            $objWriter->endElement();
1126
1127            $objWriter->endElement();
1128
1129            $objWriter->endElement();
1130
1131            // c:showVal
1132            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1133
1134            // c:showCatName
1135            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1136
1137            // c:showSerName
1138            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1139
1140            // c:showPercent
1141            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1142
1143            // c:showLeaderLines
1144            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1145
1146            $objWriter->endElement();
1147
1148            // c:spPr
1149            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
1150                // c:spPr
1151                $objWriter->startElement('c:spPr');
1152                // Write fill
1153                $this->writeFill($objWriter, $series->getFill());
1154                // ## c:spPr
1155                $objWriter->endElement();
1156            }
1157
1158            // Write X axis data
1159            $axisXData = array_keys($series->getValues());
1160
1161            // c:cat
1162            $objWriter->startElement('c:cat');
1163            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1164            $objWriter->endElement();
1165
1166            // Write Y axis data
1167            $axisYData = array_values($series->getValues());
1168
1169            // c:val
1170            $objWriter->startElement('c:val');
1171            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1172            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1173            $objWriter->endElement();
1174
1175            $objWriter->endElement();
1176
1177            ++$seriesIndex;
1178        }
1179
1180        // c:gapWidth
1181        $objWriter->startElement('c:gapWidth');
1182        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
1183        $objWriter->endElement();
1184
1185        // c:axId
1186        $objWriter->startElement('c:axId');
1187        $objWriter->writeAttribute('val', '52743552');
1188        $objWriter->endElement();
1189
1190        // c:axId
1191        $objWriter->startElement('c:axId');
1192        $objWriter->writeAttribute('val', '52749440');
1193        $objWriter->endElement();
1194
1195        // c:axId
1196        $objWriter->startElement('c:axId');
1197        $objWriter->writeAttribute('val', '0');
1198        $objWriter->endElement();
1199
1200        $objWriter->endElement();
1201    }
1202
1203    /**
1204     * Write Type Pie.
1205     *
1206     * @param XMLWriter $objWriter XML Writer
1207     */
1208    protected function writeTypeDoughnut(XMLWriter $objWriter, Doughnut $subject, bool $includeSheet = false): void
1209    {
1210        // c:pieChart
1211        $objWriter->startElement('c:doughnutChart');
1212
1213        // c:varyColors
1214        $objWriter->startElement('c:varyColors');
1215        $objWriter->writeAttribute('val', '1');
1216        $objWriter->endElement();
1217
1218        // Write series
1219        $seriesIndex = 0;
1220        foreach ($subject->getSeries() as $series) {
1221            // c:ser
1222            $objWriter->startElement('c:ser');
1223
1224            // c:idx
1225            $objWriter->startElement('c:idx');
1226            $objWriter->writeAttribute('val', $seriesIndex);
1227            $objWriter->endElement();
1228
1229            // c:order
1230            $objWriter->startElement('c:order');
1231            $objWriter->writeAttribute('val', $seriesIndex);
1232            $objWriter->endElement();
1233
1234            // c:tx
1235            $objWriter->startElement('c:tx');
1236            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1237            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1238            $objWriter->endElement();
1239
1240            // Fills for points?
1241            $dataPointFills = $series->getDataPointFills();
1242            foreach ($dataPointFills as $key => $value) {
1243                // c:dPt
1244                $objWriter->startElement('c:dPt');
1245                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1246                // c:dPt/c:spPr
1247                $objWriter->startElement('c:spPr');
1248                $this->writeFill($objWriter, $value);
1249                // c:dPt/##c:spPr
1250                $objWriter->endElement();
1251                // ##c:dPt
1252                $objWriter->endElement();
1253            }
1254
1255            // Write X axis data
1256            $axisXData = array_keys($series->getValues());
1257
1258            // c:cat
1259            $objWriter->startElement('c:cat');
1260            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1261            $objWriter->endElement();
1262
1263            // Write Y axis data
1264            $axisYData = array_values($series->getValues());
1265
1266            // c:val
1267            $objWriter->startElement('c:val');
1268            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1269            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1270            $objWriter->endElement();
1271
1272            $objWriter->endElement();
1273
1274            ++$seriesIndex;
1275        }
1276
1277        if (isset($series) && is_object($series) && $series instanceof Chart\Series) {
1278            // c:dLbls
1279            $objWriter->startElement('c:dLbls');
1280
1281            if ($series->hasDlblNumFormat()) {
1282                //c:numFmt
1283                $objWriter->startElement('c:numFmt');
1284                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1285                $objWriter->writeAttribute('sourceLinked', '0');
1286                $objWriter->endElement();
1287            }
1288
1289            // c:dLbls\c:txPr
1290            $objWriter->startElement('c:txPr');
1291            $objWriter->writeElement('a:bodyPr', null);
1292            $objWriter->writeElement('a:lstStyle', null);
1293
1294            // c:dLbls\c:txPr\a:p
1295            $objWriter->startElement('a:p');
1296
1297            // c:dLbls\c:txPr\a:p\a:pPr
1298            $objWriter->startElement('a:pPr');
1299
1300            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr
1301            $objWriter->startElement('a:defRPr');
1302            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1303            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1304            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1305            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1306            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1307            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1308            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1309
1310            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:solidFill
1311            $objWriter->startElement('a:solidFill');
1312            $this->writeColor($objWriter, $series->getFont()->getColor());
1313            $objWriter->endElement();
1314
1315            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:latin
1316            $objWriter->startElement('a:latin');
1317            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1318            $objWriter->endElement();
1319            // a:ea
1320            $objWriter->startElement('a:ea');
1321            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1322            $objWriter->endElement();
1323
1324            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\
1325            $objWriter->endElement();
1326            // c:dLbls\c:txPr\a:p\a:pPr\
1327            $objWriter->endElement();
1328
1329            // c:dLbls\c:txPr\a:p\a:endParaRPr
1330            $objWriter->startElement('a:endParaRPr');
1331            $objWriter->writeAttribute('lang', 'en-US');
1332            $objWriter->writeAttribute('dirty', '0');
1333            $objWriter->endElement();
1334
1335            // c:dLbls\c:txPr\a:p\
1336            $objWriter->endElement();
1337            // c:dLbls\c:txPr\
1338            $objWriter->endElement();
1339
1340            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1341            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1342            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1343            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1344            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1345            $this->writeElementWithValAttribute($objWriter, 'c:showBubbleSize', '0');
1346            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1347
1348            $separator = $series->getSeparator();
1349            if (!empty($separator) && PHP_EOL != $separator) {
1350                // c:dLbls\c:separator
1351                $objWriter->writeElement('c:separator', $separator);
1352            }
1353
1354            // c:dLbls\
1355            $objWriter->endElement();
1356        }
1357
1358        $this->writeElementWithValAttribute($objWriter, 'c:firstSliceAng', '0');
1359        $this->writeElementWithValAttribute($objWriter, 'c:holeSize', (string) $subject->getHoleSize());
1360
1361        $objWriter->endElement();
1362    }
1363
1364    /**
1365     * Write Type Pie.
1366     *
1367     * @param XMLWriter $objWriter XML Writer
1368     */
1369    protected function writeTypePie(XMLWriter $objWriter, Pie $subject, bool $includeSheet = false): void
1370    {
1371        // c:pieChart
1372        $objWriter->startElement('c:pieChart');
1373
1374        // c:varyColors
1375        $objWriter->startElement('c:varyColors');
1376        $objWriter->writeAttribute('val', '1');
1377        $objWriter->endElement();
1378
1379        // Write series
1380        $seriesIndex = 0;
1381        foreach ($subject->getSeries() as $series) {
1382            // c:ser
1383            $objWriter->startElement('c:ser');
1384
1385            // c:idx
1386            $objWriter->startElement('c:idx');
1387            $objWriter->writeAttribute('val', $seriesIndex);
1388            $objWriter->endElement();
1389
1390            // c:order
1391            $objWriter->startElement('c:order');
1392            $objWriter->writeAttribute('val', $seriesIndex);
1393            $objWriter->endElement();
1394
1395            // c:tx
1396            $objWriter->startElement('c:tx');
1397            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1398            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1399            $objWriter->endElement();
1400
1401            // Fills for points?
1402            $dataPointFills = $series->getDataPointFills();
1403            foreach ($dataPointFills as $key => $value) {
1404                // c:dPt
1405                $objWriter->startElement('c:dPt');
1406                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1407                // c:dPt/c:spPr
1408                $objWriter->startElement('c:spPr');
1409                $this->writeFill($objWriter, $value);
1410                // c:dPt/##c:spPr
1411                $objWriter->endElement();
1412                // ##c:dPt
1413                $objWriter->endElement();
1414            }
1415
1416            // c:dLbls
1417            $objWriter->startElement('c:dLbls');
1418
1419            if ($series->hasDlblNumFormat()) {
1420                //c:numFmt
1421                $objWriter->startElement('c:numFmt');
1422                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1423                $objWriter->writeAttribute('sourceLinked', '0');
1424                $objWriter->endElement();
1425            }
1426
1427            // c:txPr
1428            $objWriter->startElement('c:txPr');
1429
1430            // a:bodyPr
1431            $objWriter->writeElement('a:bodyPr', null);
1432
1433            // a:lstStyle
1434            $objWriter->writeElement('a:lstStyle', null);
1435
1436            // a:p
1437            $objWriter->startElement('a:p');
1438
1439            // a:pPr
1440            $objWriter->startElement('a:pPr');
1441
1442            // a:defRPr
1443            $objWriter->startElement('a:defRPr');
1444
1445            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1446            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1447            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1448            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1449            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1450            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1451            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1452
1453            // Font - a:solidFill
1454            $objWriter->startElement('a:solidFill');
1455
1456            $this->writeColor($objWriter, $series->getFont()->getColor());
1457
1458            $objWriter->endElement();
1459
1460            // Font - a:latin
1461            $objWriter->startElement('a:latin');
1462            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1463            $objWriter->endElement();
1464            // a:ea
1465            $objWriter->startElement('a:ea');
1466            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1467            $objWriter->endElement();
1468
1469            $objWriter->endElement();
1470
1471            $objWriter->endElement();
1472
1473            // a:endParaRPr
1474            $objWriter->startElement('a:endParaRPr');
1475            $objWriter->writeAttribute('lang', 'en-US');
1476            $objWriter->writeAttribute('dirty', '0');
1477            $objWriter->endElement();
1478
1479            $objWriter->endElement();
1480
1481            $objWriter->endElement();
1482
1483            // c:dLblPos
1484            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1485
1486            // c:showLegendKey
1487            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1488
1489            // c:showVal
1490            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1491
1492            // c:showCatName
1493            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1494
1495            // c:showSerName
1496            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1497
1498            // c:showPercent
1499            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1500
1501            // c:showLeaderLines
1502            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1503
1504            $objWriter->endElement();
1505
1506            // Write X axis data
1507            $axisXData = array_keys($series->getValues());
1508
1509            // c:cat
1510            $objWriter->startElement('c:cat');
1511            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1512            $objWriter->endElement();
1513
1514            // Write Y axis data
1515            $axisYData = array_values($series->getValues());
1516
1517            // c:val
1518            $objWriter->startElement('c:val');
1519            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1520            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1521            $objWriter->endElement();
1522
1523            $objWriter->endElement();
1524
1525            ++$seriesIndex;
1526        }
1527
1528        $objWriter->endElement();
1529    }
1530
1531    /**
1532     * Write Type Pie3D.
1533     *
1534     * @param XMLWriter $objWriter XML Writer
1535     */
1536    protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, bool $includeSheet = false): void
1537    {
1538        // c:pie3DChart
1539        $objWriter->startElement('c:pie3DChart');
1540
1541        // c:varyColors
1542        $objWriter->startElement('c:varyColors');
1543        $objWriter->writeAttribute('val', '1');
1544        $objWriter->endElement();
1545
1546        // Write series
1547        $seriesIndex = 0;
1548        foreach ($subject->getSeries() as $series) {
1549            // c:ser
1550            $objWriter->startElement('c:ser');
1551
1552            // c:idx
1553            $objWriter->startElement('c:idx');
1554            $objWriter->writeAttribute('val', $seriesIndex);
1555            $objWriter->endElement();
1556
1557            // c:order
1558            $objWriter->startElement('c:order');
1559            $objWriter->writeAttribute('val', $seriesIndex);
1560            $objWriter->endElement();
1561
1562            // c:tx
1563            $objWriter->startElement('c:tx');
1564            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1565            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1566            $objWriter->endElement();
1567
1568            // c:explosion
1569            $objWriter->startElement('c:explosion');
1570            $objWriter->writeAttribute('val', $subject->getExplosion());
1571            $objWriter->endElement();
1572
1573            // Fills for points?
1574            $dataPointFills = $series->getDataPointFills();
1575            foreach ($dataPointFills as $key => $value) {
1576                // c:dPt
1577                $objWriter->startElement('c:dPt');
1578                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1579                // c:dPt/c:spPr
1580                $objWriter->startElement('c:spPr');
1581                $this->writeFill($objWriter, $value);
1582                // c:dPt/##c:spPr
1583                $objWriter->endElement();
1584                // ##c:dPt
1585                $objWriter->endElement();
1586            }
1587
1588            // c:dLbls
1589            $objWriter->startElement('c:dLbls');
1590
1591            // c:txPr
1592            $objWriter->startElement('c:txPr');
1593
1594            // a:bodyPr
1595            $objWriter->writeElement('a:bodyPr', null);
1596
1597            // a:lstStyle
1598            $objWriter->writeElement('a:lstStyle', null);
1599
1600            // a:p
1601            $objWriter->startElement('a:p');
1602
1603            // a:pPr
1604            $objWriter->startElement('a:pPr');
1605
1606            // a:defRPr
1607            $objWriter->startElement('a:defRPr');
1608
1609            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1610            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1611            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1612            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1613            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1614            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1615            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1616
1617            // Font - a:solidFill
1618            $objWriter->startElement('a:solidFill');
1619
1620            $this->writeColor($objWriter, $series->getFont()->getColor());
1621
1622            $objWriter->endElement();
1623
1624            // Font - a:latin
1625            $objWriter->startElement('a:latin');
1626            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1627            $objWriter->endElement();
1628            // a:ea
1629            $objWriter->startElement('a:ea');
1630            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1631            $objWriter->endElement();
1632
1633            $objWriter->endElement();
1634
1635            $objWriter->endElement();
1636
1637            // a:endParaRPr
1638            $objWriter->startElement('a:endParaRPr');
1639            $objWriter->writeAttribute('lang', 'en-US');
1640            $objWriter->writeAttribute('dirty', '0');
1641            $objWriter->endElement();
1642
1643            $objWriter->endElement();
1644
1645            $objWriter->endElement();
1646
1647            // c:dLblPos
1648            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1649
1650            // c:showVal
1651            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1652
1653            // c:showCatName
1654            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1655
1656            // c:showSerName
1657            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1658
1659            // c:showPercent
1660            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1661
1662            // c:showLeaderLines
1663            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1664
1665            $objWriter->endElement();
1666
1667            // Write X axis data
1668            $axisXData = array_keys($series->getValues());
1669
1670            // c:cat
1671            $objWriter->startElement('c:cat');
1672            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1673            $objWriter->endElement();
1674
1675            // Write Y axis data
1676            $axisYData = array_values($series->getValues());
1677
1678            // c:val
1679            $objWriter->startElement('c:val');
1680            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1681            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1682            $objWriter->endElement();
1683
1684            $objWriter->endElement();
1685
1686            ++$seriesIndex;
1687        }
1688
1689        $objWriter->endElement();
1690    }
1691
1692    /**
1693     * Write Type Line.
1694     *
1695     * @param XMLWriter $objWriter XML Writer
1696     */
1697    protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $includeSheet = false): void
1698    {
1699        // c:lineChart
1700        $objWriter->startElement('c:lineChart');
1701
1702        // c:grouping
1703        $objWriter->startElement('c:grouping');
1704        $objWriter->writeAttribute('val', 'standard');
1705        $objWriter->endElement();
1706
1707        // Write series
1708        $seriesIndex = 0;
1709        foreach ($subject->getSeries() as $series) {
1710            // c:ser
1711            $objWriter->startElement('c:ser');
1712
1713            // c:idx
1714            $objWriter->startElement('c:idx');
1715            $objWriter->writeAttribute('val', $seriesIndex);
1716            $objWriter->endElement();
1717
1718            // c:order
1719            $objWriter->startElement('c:order');
1720            $objWriter->writeAttribute('val', $seriesIndex);
1721            $objWriter->endElement();
1722
1723            // c:tx
1724            $objWriter->startElement('c:tx');
1725            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1726            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1727            $objWriter->endElement();
1728
1729            // c:spPr
1730            $objWriter->startElement('c:spPr');
1731            // Write fill
1732            $this->writeFill($objWriter, $series->getFill());
1733            // Write outline
1734            $this->writeOutline($objWriter, $series->getOutline());
1735            // ## c:spPr
1736            $objWriter->endElement();
1737
1738            // Marker
1739            $this->writeSeriesMarker($objWriter, $series->getMarker());
1740
1741            // c:dLbls
1742            $objWriter->startElement('c:dLbls');
1743
1744            // c:txPr
1745            $objWriter->startElement('c:txPr');
1746
1747            // a:bodyPr
1748            $objWriter->writeElement('a:bodyPr', null);
1749
1750            // a:lstStyle
1751            $objWriter->writeElement('a:lstStyle', null);
1752
1753            // a:p
1754            $objWriter->startElement('a:p');
1755
1756            // a:pPr
1757            $objWriter->startElement('a:pPr');
1758
1759            // a:defRPr
1760            $objWriter->startElement('a:defRPr');
1761
1762            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1763            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1764            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1765            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1766            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1767            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1768            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1769
1770            // Font - a:solidFill
1771            $objWriter->startElement('a:solidFill');
1772
1773            $this->writeColor($objWriter, $series->getFont()->getColor());
1774
1775            $objWriter->endElement();
1776
1777            // Font - a:latin
1778            $objWriter->startElement('a:latin');
1779            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1780            $objWriter->endElement();
1781            // a:ea
1782            $objWriter->startElement('a:ea');
1783            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1784            $objWriter->endElement();
1785
1786            $objWriter->endElement();
1787
1788            $objWriter->endElement();
1789
1790            // a:endParaRPr
1791            $objWriter->startElement('a:endParaRPr');
1792            $objWriter->writeAttribute('lang', 'en-US');
1793            $objWriter->writeAttribute('dirty', '0');
1794            $objWriter->endElement();
1795
1796            $objWriter->endElement();
1797
1798            $objWriter->endElement();
1799
1800            // c:showVal
1801            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1802
1803            // c:showCatName
1804            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1805
1806            // c:showSerName
1807            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1808
1809            // c:showPercent
1810            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1811
1812            // c:showLeaderLines
1813            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1814
1815            // > c:dLbls
1816            $objWriter->endElement();
1817
1818            // Write X axis data
1819            $axisXData = array_keys($series->getValues());
1820
1821            // c:cat
1822            $objWriter->startElement('c:cat');
1823            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1824            $objWriter->endElement();
1825
1826            // Write Y axis data
1827            $axisYData = array_values($series->getValues());
1828
1829            // c:val
1830            $objWriter->startElement('c:val');
1831            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1832            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1833            $objWriter->endElement();
1834
1835            // c:smooth
1836            $objWriter->startElement('c:smooth');
1837            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
1838            $objWriter->endElement();
1839
1840            $objWriter->endElement();
1841
1842            ++$seriesIndex;
1843        }
1844
1845        // c:marker
1846        $objWriter->startElement('c:marker');
1847        $objWriter->writeAttribute('val', '1');
1848        $objWriter->endElement();
1849
1850        // c:axId
1851        $objWriter->startElement('c:axId');
1852        $objWriter->writeAttribute('val', '52743552');
1853        $objWriter->endElement();
1854
1855        // c:axId
1856        $objWriter->startElement('c:axId');
1857        $objWriter->writeAttribute('val', '52749440');
1858        $objWriter->endElement();
1859
1860        $objWriter->endElement();
1861    }
1862
1863    /**
1864     * Write Type Radar.
1865     *
1866     * @param XMLWriter $objWriter XML Writer
1867     */
1868    protected function writeTypeRadar(XMLWriter $objWriter, Radar $subject, bool $includeSheet = false): void
1869    {
1870        // c:scatterChart
1871        $objWriter->startElement('c:radarChart');
1872
1873        // c:radarStyle
1874        $objWriter->startElement('c:radarStyle');
1875        $objWriter->writeAttribute('val', 'marker');
1876        $objWriter->endElement();
1877
1878        // c:varyColors
1879        $objWriter->startElement('c:varyColors');
1880        $objWriter->writeAttribute('val', '0');
1881        $objWriter->endElement();
1882
1883        // Write series
1884        $seriesIndex = 0;
1885        foreach ($subject->getSeries() as $series) {
1886            // c:ser
1887            $objWriter->startElement('c:ser');
1888
1889            // c:idx
1890            $objWriter->startElement('c:idx');
1891            $objWriter->writeAttribute('val', $seriesIndex);
1892            $objWriter->endElement();
1893
1894            // c:order
1895            $objWriter->startElement('c:order');
1896            $objWriter->writeAttribute('val', $seriesIndex);
1897            $objWriter->endElement();
1898
1899            // c:tx
1900            $objWriter->startElement('c:tx');
1901            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1902            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1903            $objWriter->endElement();
1904
1905            // c:spPr
1906            $objWriter->startElement('c:spPr');
1907            // Write fill
1908            $this->writeFill($objWriter, $series->getFill());
1909            // Write outline
1910            $this->writeOutline($objWriter, $series->getOutline());
1911            // ## c:spPr
1912            $objWriter->endElement();
1913
1914            // Marker
1915            $this->writeSeriesMarker($objWriter, $series->getMarker());
1916
1917            // c:dLbls
1918            $objWriter->startElement('c:dLbls');
1919
1920            // c:txPr
1921            $objWriter->startElement('c:txPr');
1922
1923            // a:bodyPr
1924            $objWriter->writeElement('a:bodyPr', null);
1925
1926            // a:lstStyle
1927            $objWriter->writeElement('a:lstStyle', null);
1928
1929            // a:p
1930            $objWriter->startElement('a:p');
1931
1932            // a:pPr
1933            $objWriter->startElement('a:pPr');
1934
1935            // a:defRPr
1936            $objWriter->startElement('a:defRPr');
1937
1938            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1939            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1940            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1941            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1942            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1943            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000');
1944            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000');
1945
1946            // Font - a:solidFill
1947            $objWriter->startElement('a:solidFill');
1948
1949            $this->writeColor($objWriter, $series->getFont()->getColor());
1950
1951            $objWriter->endElement();
1952
1953            // Font - a:latin
1954            $objWriter->startElement('a:latin');
1955            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1956            $objWriter->endElement();
1957            // a:ea
1958            $objWriter->startElement('a:ea');
1959            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1960            $objWriter->endElement();
1961
1962            $objWriter->endElement();
1963
1964            $objWriter->endElement();
1965
1966            // a:endParaRPr
1967            $objWriter->startElement('a:endParaRPr');
1968            $objWriter->writeAttribute('lang', 'en-US');
1969            $objWriter->writeAttribute('dirty', '0');
1970            $objWriter->endElement();
1971
1972            $objWriter->endElement();
1973
1974            $objWriter->endElement();
1975
1976            // c:showLegendKey
1977            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1978
1979            // c:showVal
1980            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1981
1982            // c:showCatName
1983            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1984
1985            // c:showSerName
1986            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1987
1988            // c:showPercent
1989            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1990
1991            // c:showLeaderLines
1992            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1993
1994            $objWriter->endElement();
1995
1996            // Write X axis data
1997            $axisXData = array_keys($series->getValues());
1998
1999            // c:cat
2000            $objWriter->startElement('c:cat');
2001            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2002            $objWriter->endElement();
2003
2004            // Write Y axis data
2005            $axisYData = array_values($series->getValues());
2006
2007            // c:val
2008            $objWriter->startElement('c:val');
2009            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
2010            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2011            $objWriter->endElement();
2012
2013            $objWriter->endElement();
2014
2015            ++$seriesIndex;
2016        }
2017
2018        // c:axId
2019        $objWriter->startElement('c:axId');
2020        $objWriter->writeAttribute('val', '52743552');
2021        $objWriter->endElement();
2022
2023        // c:axId
2024        $objWriter->startElement('c:axId');
2025        $objWriter->writeAttribute('val', '52749440');
2026        $objWriter->endElement();
2027
2028        $objWriter->endElement();
2029    }
2030
2031    /**
2032     * Write Type Scatter.
2033     */
2034    protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, bool $includeSheet = false): void
2035    {
2036        // c:scatterChart
2037        $objWriter->startElement('c:scatterChart');
2038
2039        // c:scatterStyle
2040        $objWriter->startElement('c:scatterStyle');
2041        $objWriter->writeAttribute('val', 'lineMarker');
2042        $objWriter->endElement();
2043
2044        // c:varyColors
2045        $objWriter->startElement('c:varyColors');
2046        $objWriter->writeAttribute('val', '0');
2047        $objWriter->endElement();
2048
2049        // Write series
2050        $seriesIndex = 0;
2051        foreach ($subject->getSeries() as $series) {
2052            // c:ser
2053            $objWriter->startElement('c:ser');
2054
2055            // c:idx
2056            $objWriter->startElement('c:idx');
2057            $objWriter->writeAttribute('val', $seriesIndex);
2058            $objWriter->endElement();
2059
2060            // c:order
2061            $objWriter->startElement('c:order');
2062            $objWriter->writeAttribute('val', $seriesIndex);
2063            $objWriter->endElement();
2064
2065            // c:tx
2066            $objWriter->startElement('c:tx');
2067            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
2068            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
2069            $objWriter->endElement();
2070
2071            // c:spPr
2072            $objWriter->startElement('c:spPr');
2073            // Write fill
2074            $this->writeFill($objWriter, $series->getFill());
2075            // Write outline
2076            $this->writeOutline($objWriter, $series->getOutline());
2077            // ## c:spPr
2078            $objWriter->endElement();
2079
2080            // Marker
2081            $this->writeSeriesMarker($objWriter, $series->getMarker());
2082
2083            // c:dLbls
2084            $objWriter->startElement('c:dLbls');
2085
2086            // c:txPr
2087            $objWriter->startElement('c:txPr');
2088
2089            // a:bodyPr
2090            $objWriter->writeElement('a:bodyPr', null);
2091
2092            // a:lstStyle
2093            $objWriter->writeElement('a:lstStyle', null);
2094
2095            // a:p
2096            $objWriter->startElement('a:p');
2097
2098            // a:pPr
2099            $objWriter->startElement('a:pPr');
2100
2101            // a:defRPr
2102            $objWriter->startElement('a:defRPr');
2103
2104            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
2105            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
2106            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2107            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
2108            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
2109            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
2110            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
2111
2112            // Font - a:solidFill
2113            $objWriter->startElement('a:solidFill');
2114
2115            $this->writeColor($objWriter, $series->getFont()->getColor());
2116
2117            $objWriter->endElement();
2118
2119            // Font - a:latin
2120            $objWriter->startElement('a:latin');
2121            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2122            $objWriter->endElement();
2123            // a:ea
2124            $objWriter->startElement('a:ea');
2125            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2126            $objWriter->endElement();
2127
2128            $objWriter->endElement();
2129
2130            $objWriter->endElement();
2131
2132            // a:endParaRPr
2133            $objWriter->startElement('a:endParaRPr');
2134            $objWriter->writeAttribute('lang', 'en-US');
2135            $objWriter->writeAttribute('dirty', '0');
2136            $objWriter->endElement();
2137
2138            $objWriter->endElement();
2139
2140            $objWriter->endElement();
2141
2142            // c:showLegendKey
2143            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
2144
2145            // c:showVal
2146            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
2147
2148            // c:showCatName
2149            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
2150
2151            // c:showSerName
2152            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
2153
2154            // c:showPercent
2155            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
2156
2157            // c:separator
2158            $separator = $series->getSeparator();
2159            if (!empty($separator) && PHP_EOL != $separator) {
2160                // c:dLbls\c:separator
2161                $objWriter->writeElement('c:separator', $separator);
2162            }
2163
2164            // c:showLeaderLines
2165            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
2166
2167            $objWriter->endElement();
2168
2169            // Write X axis data
2170            $axisXData = array_keys($series->getValues());
2171
2172            // c:xVal
2173            $objWriter->startElement('c:xVal');
2174            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2175            $objWriter->endElement();
2176
2177            // Write Y axis data
2178            $axisYData = array_values($series->getValues());
2179
2180            // c:yVal
2181            $objWriter->startElement('c:yVal');
2182            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
2183            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2184            $objWriter->endElement();
2185
2186            // c:smooth
2187            $objWriter->startElement('c:smooth');
2188            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
2189            $objWriter->endElement();
2190
2191            $objWriter->endElement();
2192
2193            ++$seriesIndex;
2194        }
2195
2196        // c:axId
2197        $objWriter->startElement('c:axId');
2198        $objWriter->writeAttribute('val', '52743552');
2199        $objWriter->endElement();
2200
2201        // c:axId
2202        $objWriter->startElement('c:axId');
2203        $objWriter->writeAttribute('val', '52749440');
2204        $objWriter->endElement();
2205
2206        $objWriter->endElement();
2207    }
2208
2209    /**
2210     * Write chart relationships to XML format.
2211     *
2212     * @return string XML Output
2213     */
2214    protected function writeChartRelationships(Chart $pChart): string
2215    {
2216        // Create XML writer
2217        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
2218
2219        // XML header
2220        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
2221
2222        // Relationships
2223        $objWriter->startElement('Relationships');
2224        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
2225
2226        // Write spreadsheet relationship?
2227        if ($pChart->hasIncludedSpreadsheet()) {
2228            $this->writeRelationship($objWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/package', '../embeddings/' . $pChart->getIndexedFilename() . '.xlsx');
2229        }
2230
2231        $objWriter->endElement();
2232
2233        // Return
2234        return $objWriter->getData();
2235    }
2236
2237    protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $marker): void
2238    {
2239        // c:marker
2240        $objWriter->startElement('c:marker');
2241        // c:marker > c:symbol
2242        $objWriter->startElement('c:symbol');
2243        $objWriter->writeAttribute('val', $marker->getSymbol());
2244        $objWriter->endElement();
2245
2246        // Size if different of none
2247        if (Chart\Marker::SYMBOL_NONE != $marker->getSymbol()) {
2248            $markerSize = (int) $marker->getSize();
2249            if ($markerSize < 2) {
2250                $markerSize = 2;
2251            }
2252            if ($markerSize > 72) {
2253                $markerSize = 72;
2254            }
2255
2256            /*
2257             * c:marker > c:size
2258             * Size in points
2259             * @link : https://msdn.microsoft.com/en-us/library/hh658135(v=office.12).aspx
2260             */
2261            $objWriter->startElement('c:size');
2262            $objWriter->writeAttribute('val', $markerSize);
2263            $objWriter->endElement();
2264        }
2265
2266        // // c:marker > c:spPr
2267        $objWriter->startElement('c:spPr');
2268        $this->writeFill($objWriter, $marker->getFill());
2269        $this->writeBorder($objWriter, $marker->getBorder(), '', true);
2270        $objWriter->endElement();
2271
2272        // > c:marker
2273        $objWriter->endElement();
2274    }
2275
2276    protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, string $typeAxis, Chart\Type\AbstractType $typeChart): void
2277    {
2278        if (Chart\Axis::AXIS_X != $typeAxis && Chart\Axis::AXIS_Y != $typeAxis) {
2279            return;
2280        }
2281
2282        $crossesAt = $oAxis->getCrossesAt();
2283        $orientation = $oAxis->isReversedOrder() ? 'maxMin' : 'minMax';
2284
2285        if (Chart\Axis::AXIS_X == $typeAxis) {
2286            $mainElement = 'c:catAx';
2287            $axIdVal = '52743552';
2288            $axPosVal = $crossesAt === 'max' ? 't' : 'b';
2289            $crossAxVal = '52749440';
2290        } else {
2291            $mainElement = 'c:valAx';
2292            $axIdVal = '52749440';
2293            $axPosVal = $crossesAt === 'max' ? 'r' : 'l';
2294            $crossAxVal = '52743552';
2295        }
2296
2297        // $mainElement
2298        $objWriter->startElement($mainElement);
2299
2300        // $mainElement > c:axId
2301        $objWriter->startElement('c:axId');
2302        $objWriter->writeAttribute('val', $axIdVal);
2303        $objWriter->endElement();
2304
2305        // $mainElement > c:scaling
2306        $objWriter->startElement('c:scaling');
2307
2308        // $mainElement > c:scaling > c:orientation
2309        $objWriter->startElement('c:orientation');
2310        $objWriter->writeAttribute('val', $orientation);
2311        $objWriter->endElement();
2312
2313        if (null !== $oAxis->getMaxBounds()) {
2314            $objWriter->startElement('c:max');
2315            $objWriter->writeAttribute('val', $oAxis->getMaxBounds());
2316            $objWriter->endElement();
2317        }
2318
2319        if (null !== $oAxis->getMinBounds()) {
2320            $objWriter->startElement('c:min');
2321            $objWriter->writeAttribute('val', $oAxis->getMinBounds());
2322            $objWriter->endElement();
2323        }
2324
2325        // $mainElement > ##c:scaling
2326        $objWriter->endElement();
2327
2328        // $mainElement > c:delete
2329        $objWriter->startElement('c:delete');
2330        $objWriter->writeAttribute('val', $oAxis->isVisible() ? '0' : '1');
2331        $objWriter->endElement();
2332
2333        // $mainElement > c:axPos
2334        $objWriter->startElement('c:axPos');
2335        $objWriter->writeAttribute('val', $axPosVal);
2336        $objWriter->endElement();
2337
2338        $oMajorGridlines = $oAxis->getMajorGridlines();
2339        if ($oMajorGridlines instanceof Gridlines) {
2340            $objWriter->startElement('c:majorGridlines');
2341
2342            $this->writeAxisGridlines($objWriter, $oMajorGridlines);
2343
2344            $objWriter->endElement();
2345        }
2346
2347        $oMinorGridlines = $oAxis->getMinorGridlines();
2348        if ($oMinorGridlines instanceof Gridlines) {
2349            $objWriter->startElement('c:minorGridlines');
2350
2351            $this->writeAxisGridlines($objWriter, $oMinorGridlines);
2352
2353            $objWriter->endElement();
2354        }
2355
2356        if ('' != $oAxis->getTitle()) {
2357            // c:title
2358            $objWriter->startElement('c:title');
2359
2360            // c:tx
2361            $objWriter->startElement('c:tx');
2362
2363            // c:rich
2364            $objWriter->startElement('c:rich');
2365
2366            // a:bodyPr
2367            $objWriter->startElement('a:bodyPr');
2368            $objWriter->writeAttributeIf($oAxis->getTitleRotation() != 0, 'rot', CommonDrawing::degreesToAngle((int) $oAxis->getTitleRotation()));
2369            $objWriter->endElement();
2370
2371            // a:lstStyle
2372            $objWriter->writeElement('a:lstStyle', null);
2373
2374            // a:p
2375            $objWriter->startElement('a:p');
2376
2377            // a:pPr
2378            $objWriter->startElement('a:pPr');
2379
2380            // a:defRPr
2381            $objWriter->startElement('a:defRPr');
2382
2383            $objWriter->writeAttribute('b', ($oAxis->getFont()->isBold() ? 'true' : 'false'));
2384            $objWriter->writeAttribute('i', ($oAxis->getFont()->isItalic() ? 'true' : 'false'));
2385            $objWriter->writeAttribute('strike', ($oAxis->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2386            $objWriter->writeAttribute('sz', ($oAxis->getFont()->getSize() * 100));
2387            $objWriter->writeAttribute('u', $oAxis->getFont()->getUnderline());
2388            $objWriter->writeAttributeIf($oAxis->getFont()->isSuperScript(), 'baseline', '300000');
2389            $objWriter->writeAttributeIf($oAxis->getFont()->isSubScript(), 'baseline', '-250000');
2390
2391            // Font - a:solidFill
2392            $objWriter->startElement('a:solidFill');
2393            $this->writeColor($objWriter, $oAxis->getFont()->getColor());
2394            $objWriter->endElement();
2395
2396            // Font - a:latin
2397            $objWriter->startElement('a:latin');
2398            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2399            $objWriter->endElement();
2400            // a:ea
2401            $objWriter->startElement('a:ea');
2402            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2403            $objWriter->endElement();
2404
2405            $objWriter->endElement();
2406
2407            // ## a:pPr
2408            $objWriter->endElement();
2409
2410            // a:r
2411            $objWriter->startElement('a:r');
2412
2413            // a:rPr
2414            $objWriter->startElement('a:rPr');
2415            $objWriter->writeAttribute('lang', 'en-US');
2416            $objWriter->writeAttribute('dirty', '0');
2417            $objWriter->endElement();
2418
2419            // a:t
2420            $objWriter->writeElement('a:t', $oAxis->getTitle());
2421
2422            // ## a:r
2423            $objWriter->endElement();
2424
2425            // a:endParaRPr
2426            $objWriter->startElement('a:endParaRPr');
2427            $objWriter->writeAttribute('lang', 'en-US');
2428            $objWriter->writeAttribute('dirty', '0');
2429            $objWriter->endElement();
2430
2431            // ## a:p
2432            $objWriter->endElement();
2433
2434            // ## c:rich
2435            $objWriter->endElement();
2436
2437            // ## c:tx
2438            $objWriter->endElement();
2439
2440            // ## c:title
2441            $objWriter->endElement();
2442        }
2443
2444        // c:numFmt
2445        $objWriter->startElement('c:numFmt');
2446        $objWriter->writeAttribute('formatCode', $oAxis->getFormatCode());
2447        $objWriter->writeAttribute('sourceLinked', '1');
2448        $objWriter->endElement();
2449
2450        // c:majorTickMark
2451        $objWriter->startElement('c:majorTickMark');
2452        $objWriter->writeAttribute('val', $oAxis->getMajorTickMark());
2453        $objWriter->endElement();
2454
2455        // c:minorTickMark
2456        $objWriter->startElement('c:minorTickMark');
2457        $objWriter->writeAttribute('val', $oAxis->getMinorTickMark());
2458        $objWriter->endElement();
2459
2460        // c:tickLblPos
2461        $objWriter->startElement('c:tickLblPos');
2462        $objWriter->writeAttribute('val', $oAxis->getTickLabelPosition());
2463        $objWriter->endElement();
2464
2465        // c:spPr
2466        $objWriter->startElement('c:spPr');
2467        $this->writeOutline($objWriter, $oAxis->getOutline());
2468        $objWriter->endElement();
2469
2470        // c:txPr
2471        $objWriter->startElement('c:txPr');
2472
2473        // a:bodyPr
2474        $objWriter->writeElement('a:bodyPr', null);
2475
2476        // a:lstStyle
2477        $objWriter->writeElement('a:lstStyle', null);
2478
2479        // a:p
2480        $objWriter->startElement('a:p');
2481
2482        // a:pPr
2483        $objWriter->startElement('a:pPr');
2484
2485        // a:defRPr
2486        $objWriter->startElement('a:defRPr');
2487        $objWriter->writeAttribute('b', ($oAxis->getTickLabelFont()->isBold() ? 'true' : 'false'));
2488        $objWriter->writeAttribute('i', ($oAxis->getTickLabelFont()->isItalic() ? 'true' : 'false'));
2489        $objWriter->writeAttribute('strike', ($oAxis->getTickLabelFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2490        $objWriter->writeAttribute('sz', ($oAxis->getTickLabelFont()->getSize() * 100));
2491        $objWriter->writeAttribute('u', $oAxis->getTickLabelFont()->getUnderline());
2492        $objWriter->writeAttributeIf($oAxis->getTickLabelFont()->isSuperScript(), 'baseline', '300000');
2493        $objWriter->writeAttributeIf($oAxis->getTickLabelFont()->isSubScript(), 'baseline', '-250000');
2494
2495        // Font - a:solidFill
2496        $objWriter->startElement('a:solidFill');
2497        $this->writeColor($objWriter, $oAxis->getTickLabelFont()->getColor());
2498        $objWriter->endElement();
2499
2500        // Font - a:latin
2501        $objWriter->startElement('a:latin');
2502        $objWriter->writeAttribute('typeface', $oAxis->getTickLabelFont()->getName());
2503        $objWriter->endElement();
2504
2505        // Font - a:ea
2506        $objWriter->startElement('a:ea');
2507        $objWriter->writeAttribute('typeface', $oAxis->getTickLabelFont()->getName());
2508        $objWriter->endElement();
2509
2510        //## a:defRPr
2511        $objWriter->endElement();
2512
2513        //## a:pPr
2514        $objWriter->endElement();
2515
2516        // a:endParaRPr
2517        $objWriter->startElement('a:endParaRPr');
2518        $objWriter->writeAttribute('lang', 'en-US');
2519        $objWriter->writeAttribute('dirty', '0');
2520        $objWriter->endElement();
2521
2522        // ## a:p
2523        $objWriter->endElement();
2524
2525        // ## c:txPr
2526        $objWriter->endElement();
2527
2528        // c:crossAx
2529        $objWriter->startElement('c:crossAx');
2530        $objWriter->writeAttribute('val', $crossAxVal);
2531        $objWriter->endElement();
2532
2533        // c:crosses "autoZero" | "min" | "max" | custom string value
2534        if (in_array($crossesAt, ['autoZero', 'min', 'max'])) {
2535            $objWriter->startElement('c:crosses');
2536            $objWriter->writeAttribute('val', $crossesAt);
2537            $objWriter->endElement();
2538        } else {
2539            $objWriter->startElement('c:crossesAt');
2540            $objWriter->writeAttribute('val', $crossesAt);
2541            $objWriter->endElement();
2542        }
2543
2544        if (Chart\Axis::AXIS_X == $typeAxis) {
2545            // c:lblAlgn
2546            $objWriter->startElement('c:lblAlgn');
2547            $objWriter->writeAttribute('val', 'ctr');
2548            $objWriter->endElement();
2549
2550            // c:lblOffset
2551            $objWriter->startElement('c:lblOffset');
2552            $objWriter->writeAttribute('val', '100');
2553            $objWriter->endElement();
2554
2555            // c:majorUnit
2556            if ($oAxis->getMajorUnit() !== null) {
2557                $objWriter->startElement('c:tickLblSkip');
2558                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2559                $objWriter->endElement();
2560            }
2561        }
2562
2563        if (Chart\Axis::AXIS_Y == $typeAxis) {
2564            // c:crossBetween
2565            $objWriter->startElement('c:crossBetween');
2566            // midCat : Position Axis On Tick Marks
2567            // between : Between Tick Marks
2568            if ($typeChart instanceof Area) {
2569                $objWriter->writeAttribute('val', 'midCat');
2570            } else {
2571                $objWriter->writeAttribute('val', 'between');
2572            }
2573            $objWriter->endElement();
2574
2575            // c:majorUnit
2576            if ($oAxis->getMajorUnit() !== null) {
2577                $objWriter->startElement('c:majorUnit');
2578                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2579                $objWriter->endElement();
2580            }
2581
2582            // c:minorUnit
2583            if ($oAxis->getMinorUnit() !== null) {
2584                $objWriter->startElement('c:minorUnit');
2585                $objWriter->writeAttribute('val', $oAxis->getMinorUnit());
2586                $objWriter->endElement();
2587            }
2588        }
2589
2590        $objWriter->endElement();
2591    }
2592
2593    protected function writeAxisGridlines(XMLWriter $objWriter, Gridlines $oGridlines): void
2594    {
2595        // c:spPr
2596        $objWriter->startElement('c:spPr');
2597
2598        // Outline
2599        $this->writeOutline($objWriter, $oGridlines->getOutline());
2600
2601        // ##c:spPr
2602        $objWriter->endElement();
2603    }
2604}